const ALPHABET: [u8; 32] = *b"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";

// 反查表：非法=255，其它为 0..31
static DECODE: [u8; 256] = {
    let mut t = [255u8; 256];
    let mut i = 0u8;
    // A-Z
    while i < 26 {
        t[b'A' as usize + i as usize] = i;
        t[b'a' as usize + i as usize] = i;
        i += 1;
    }
    // 2-7 -> 26..31
    let mut d = 0u8;
    while d < 6 {
        t[b'2' as usize + d as usize] = 26 + d;
        d += 1;
    }
    t
};

#[inline]
fn zigzag_i32(x: i32) -> u32 {
    ((x << 1) ^ (x >> 31)) as u32
}
#[inline]
fn unzigzag_u32(u: u32) -> i32 {
    ((u >> 1) as i32) ^ (-((u & 1) as i32))
}

/// 把 (x,y,z) 区块坐标编码为 20 字符 RFC4648 Base32（无填充）
/// 格式：ZigZag(x)|ZigZag(y)|ZigZag(z) 共 96bit，左移 4bit -> 100bit -> 20×5bit
#[inline]
pub fn encode_coord(x: i32, y: i32, z: i32) -> String {
    let xx = zigzag_i32(x) as u128;
    let yy = zigzag_i32(y) as u128;
    let zz = zigzag_i32(z) as u128;

    // 拼成 96 位： [xx(32)][yy(32)][zz(32)]
    let mut v = (xx << 64) | (yy << 32) | zz;

    // 左移 4 位，得到 100 位有效数据，正好 20 个 Base32 字符
    v <<= 4;

    // 逐 5 位切片（从高到低），写入固定 20 字节缓冲
    let mut buf = [0u8; 20];
    let mut i = 0;
    while i < 20 {
        let idx = ((v >> 95) & 0x1F) as usize;
        buf[i] = ALPHABET[idx];
        v <<= 5;
        i += 1;
    }
    // 安全创建字符串
    unsafe { String::from_utf8_unchecked(buf.to_vec()) }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DecodeError {
    InvalidChar(u8),
    InvalidLength, // 必须恰好 20 字符
}

/// 解码 20 字符 Base32（大小写不敏感，不允许分隔符）
#[inline]
pub fn decode_coord(s: &str) -> Result<(i32, i32, i32), DecodeError> {
    let bytes = s.as_bytes();
    if bytes.len() != 20 {
        return Err(DecodeError::InvalidLength);
    }

    // 回拼 100 位
    let mut v: u128 = 0;
    for &b in bytes {
        let d = DECODE[b as usize];
        if d == 255 {
            return Err(DecodeError::InvalidChar(b));
        }
        v = (v << 5) | (d as u128);
    }

    // 去掉前置 4 位填充 -> 96 位：xx|yy|zz
    v >>= 4;

    let zz = (v & 0xFFFF_FFFF) as u32;
    let yy = ((v >> 32) & 0xFFFF_FFFF) as u32;
    let xx = ((v >> 64) & 0xFFFF_FFFF) as u32;

    Ok((unzigzag_u32(xx), unzigzag_u32(yy), unzigzag_u32(zz)))
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_encode_decode() {
        let coord = (100, 200, 300);
        let encoded = encode_coord(coord.0, coord.1, coord.2);
        let decoded = decode_coord(&encoded).unwrap();
        println!("encoded: {}", encoded);
        println!("decoded: {:?}", decoded);
        assert_eq!(decoded, coord);
    }
}
